<!DOCTYPE html>


<html lang="zh-Hans">


<head>
  <meta charset="utf-8" />
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
     40+岁大龄码农的自我修养
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">
  
<link rel="stylesheet" href="/css/custom.css">

  
  <script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>
  
  

  

<link rel="alternate" href="/atom.xml" title="40+岁大龄码农的自我修养" type="application/atom+xml">
</head>

</html>

<body>
  <div id="app">
    
      
    <main class="content on">
      



<!-- Subtitle -->

<div id="main">
  <section class="outer">
  
  
  <article class="articles">
    
    
    
    
    <article
  id="post-vagran-setting"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/01/08/vagran-setting/"
    >vagrant的安装和设置</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/01/08/vagran-setting/" class="article-date">
  <time datetime="2019-01-08T02:08:20.000Z" itemprop="datePublished">2019-01-08</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <ul>
<li><p>下载和安装</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://www.vagrantup.com/downloads.html">vagrant官方网址</a> , 下载后双击安装</li>
<li><a target="_blank" rel="noopener" href="https://www.virtualbox.org/wiki/Downloads">VirtualBox官方网址</a> , 下载后双击安装</li>
</ul>
</li>
<li><p>vagrant 官方box的下载方法:</p>
<ul>
<li><p>参考 <a target="_blank" rel="noopener" href="https://my.oschina.net/cxgphper/blog/1940644">vagrant 的 box 哪里下？镜像在哪儿找？教你在 vagrant 官网下载各种最新. box 资源</a></p>
</li>
<li><p>进入<a target="_blank" rel="noopener" href="https://app.vagrantup.com/centos/boxes/7">Vagrant box</a>找到centos box镜像最新的版本号</p>
</li>
<li><p>拼接下载链接</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https:&#x2F;&#x2F;app.vagrantup.com&#x2F;centos&#x2F;boxes&#x2F;7&#x2F;versions&#x2F;&#123;版本号&#125;&#x2F;providers&#x2F;virtualbox.box</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>初始化vagrant</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mkdir centos &amp;&amp; cd centos # 新建centos目录</span><br><span class="line">vagrant box add centos_base d:&#x2F;vagrant_images&#x2F;vagrant-centos-7.2.box # 添加镜像到vagrant</span><br><span class="line">vagrant init centos_base # 初始化配置</span><br></pre></td></tr></table></figure></li>
<li><p>修改vagrant配置</p>
<ul>
<li>单台虚拟机的配置, 参考: <a target="_blank" rel="noopener" href="https://www.jianshu.com/p/2724cd5f28e5">Vagrant 实战</a></li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">#Vagrant的三种网络配置</span><br><span class="line">  #端口映射(Forwarded port) 把宿主计算机的端口映射到虚拟机的某一个端口上，访问宿主计算机端口时，请求实际是被转发到虚拟机上指定端口的。</span><br><span class="line">  #例如下面的配置，将访问宿主计算机8080端口的请求都转发到虚拟机的80端口上进行处理       #访问localhost:8080,对应访问虚拟机的80端口</span><br><span class="line">  #优点：容易实现外网访问虚拟机</span><br><span class="line">  #缺点：端口比较多时，配置麻烦；不支持在宿主机器上使用小于1024的端口来转发。比如：不能使用SSL的443端口来进行https连接。</span><br><span class="line">  config.vm.network &quot;forwarded_port&quot;, guest: 80, host: 8080</span><br><span class="line">  </span><br><span class="line">  #私有网络（Private network） ，只有主机可以访问虚拟机，如果多个虚拟机设定在同一个网段也可以互相访问，当然虚拟机是可以访问外部网络的。</span><br><span class="line">  #优点：安全，只有自己能访问</span><br><span class="line">  #缺点：因为私有的原因，所以团队成员其他人不能和你协作</span><br><span class="line">  config.vm.network &quot;private_network&quot;, ip: &quot;192.168.33.10&quot;</span><br><span class="line">  </span><br><span class="line">  #公有网络（Public network） ，虚拟机享受实体机器一样的待遇，一样的网络配置，vagrant1.3版本之后也可以设定静态IP。</span><br><span class="line">  #优点：方便团队协作，别人可以访问你的虚拟机</span><br><span class="line">  #缺点：需要有网络，有路由器分配IP</span><br><span class="line">  config.vm.network &quot;public_network&quot;, ip: &quot;192.168.12.253&quot;</span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line">  #设置文件同步，如下 ..&#x2F;work 是本地目录， &#x2F;vagrant_data是虚拟机文件目录</span><br><span class="line">  #两个目录设置为同步，这样就可以直接本地编辑文件，使用虚拟机配置的软件环境了。</span><br><span class="line">  config.vm.synced_folder &quot;..&#x2F;work&quot;, &quot;&#x2F;vagrant_data&quot;,</span><br><span class="line">  :mount_options &#x3D;&gt; [&quot;dmode&#x3D;775&quot;,&quot;fmode&#x3D;664&quot;]</span><br><span class="line">  </span><br><span class="line">  # 设置虚拟机的内存</span><br><span class="line">  config.vm.provider &quot;virtualbox&quot; do |vb|</span><br><span class="line">     vb.memory &#x3D; &quot;4096&quot;</span><br><span class="line">  end</span><br><span class="line">  </span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li>多台虚拟机的配置, 参考: <a target="_blank" rel="noopener" href="https://blog.csdn.net/hel12he/article/details/51089774">vagrant系列二：vagrant的配置文件vagrantfile详解</a></li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Vagrant.configure(&quot;2&quot;) do |config|</span><br><span class="line">  config.vm.define :web do |web|</span><br><span class="line">    web.vm.provider &quot;virtualbox&quot; do |v|</span><br><span class="line">          v.customize [&quot;modifyvm&quot;, :id, &quot;--name&quot;, &quot;web&quot;, &quot;--memory&quot;, &quot;512&quot;]</span><br><span class="line">    end</span><br><span class="line">    web.vm.box &#x3D; &quot;CentOs7&quot;</span><br><span class="line">    web.vm.hostname &#x3D; &quot;web&quot;</span><br><span class="line">    web.vm.network :private_network, ip: &quot;192.168.33.10&quot;</span><br><span class="line">  end</span><br><span class="line"></span><br><span class="line">  config.vm.define :redis do |redis|</span><br><span class="line">    redis.vm.provider &quot;virtualbox&quot; do |v|</span><br><span class="line">          v.customize [&quot;modifyvm&quot;, :id, &quot;--name&quot;, &quot;redis&quot;, &quot;--memory&quot;, &quot;512&quot;]</span><br><span class="line">    end</span><br><span class="line">    redis.vm.box &#x3D; &quot;CentOs7&quot;</span><br><span class="line">    redis.vm.hostname &#x3D; &quot;redis&quot;</span><br><span class="line">    redis.vm.network :private_network, ip: &quot;192.168.33.11&quot;</span><br><span class="line">  end</span><br><span class="line">end</span><br></pre></td></tr></table></figure></li>
<li><p>v1811.02版本centos box需要修改sshd的设置, 改成ssh允许用户名和密码登录</p>
<ul>
<li><p>参考 <a target="_blank" rel="noopener" href="https://blog.csdn.net/zjqlovell/article/details/79399265">CentOS SSH 密钥登陆改为密码登陆</a></p>
</li>
<li><p>用<code>vagrant ssh</code>命令进入centos</p>
</li>
<li><p>打开/etc/ssh/sshd_config</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">vim &#x2F;etc&#x2F;ssh&#x2F;sshd_config</span><br><span class="line">PermitRootLogin yes 删除前面的 #注释</span><br><span class="line">PasswordAuthentication no 改成 PasswordAuthentication yes</span><br></pre></td></tr></table></figure></li>
<li><p>重启sshd</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service sshd restart</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>启动和ssh链接, vagrant镜像有两个user,  root和vagrant, 密码都是: vagrant, 开启xshell, 填入ip(192.168.33.10), 用户root和密码vagrant</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">vagrant up  # 启动虚拟机</span><br><span class="line">vagrant halt  # 关闭虚拟机</span><br><span class="line">vagrant reload  # 重启虚拟机</span><br><span class="line">vagrant ssh  # SSH 至虚拟机</span><br><span class="line">vagrant status  # 查看虚拟机运行状态</span><br><span class="line">vagrant destroy  # 销毁当前虚拟机</span><br></pre></td></tr></table></figure></li>
<li><p>打包</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vagrant package --vagrantfile Vagrantfile #将配置文件一块打包</span><br><span class="line">vagrant package --output centos.box # 要打包成的box名称，不会自动添加.box后缀，要手动加.默认值package.box</span><br></pre></td></tr></table></figure></li>
<li><p>pycharm 的python项目用vagrant虚拟环境的python作为解释器, 参考 <a target="_blank" rel="noopener" href="https://pengzhendong.cn/2018/05/26/Pycharm-python-interpreter/">Pycharm 解释器配置</a></p>
</li>
<li><p>pycharm 配置terminal为vagrant虚拟机环境,</p>
</li>
</ul>
<ul>
<li>开启ssh terminal, 勾选为current vagrant, 编码设置为utf-8</li>
</ul>
<p>  <img src="https://gitee.com/clutchbear/pic/raw/master/image/005YhI8igy1fx8kl17blhj311n0ix75n.png"></p>
<ul>
<li><p>tools选择start ssh sessions</p>
<p><img src="https://gitee.com/clutchbear/pic/raw/master/image/005YhI8igy1fx8kmt5iq4j309w0atmxp.png"></p>
</li>
</ul>
<ul>
<li><p>在terminal中就可以直接使用远程terminal</p>
<p><img src="https://gitee.com/clutchbear/pic/raw/master/image/005YhI8igy1fx8kog1jsoj30rv0c3t9l.png"></p>
</li>
<li><p>mysql连接速度慢的解决方法</p>
<ul>
<li><p>参考: <a target="_blank" rel="noopener" href="https://talk.ninghao.net/t/lian-jie-vagrantzhong-mysqlbian-man-liao-shi-shi-yao-yuan-yin/3521">连接Vagrant中mysql变慢了是什么原因</a></p>
</li>
<li><p>打开mysql的配置文件<code>/etc/my.conf</code>,  增加<code>skip-name-resolve</code>参数</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line">skip-name-resolve</span><br></pre></td></tr></table></figure></li>
<li><p>重启mysql</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service mysqld restart</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<ul>
<li><p>ssh 连接速度慢的解决方法</p>
<ul>
<li><p>编辑 /etc/ssh/sshd_config</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">UseDNS no, 找到此行取消注释,并且把yes改成no</span><br></pre></td></tr></table></figure></li>
<li><p>重启ssh</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service sshd restart</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>出现文件夹同步失败的解决方法</p>
<ul>
<li><p>参考 <a target="_blank" rel="noopener" href="https://zj-john.github.io/tips/cjhpvs7vl000r64f01suposfq.html">vagrant up报错：unable to mount VirtualBox shared folders</a></p>
</li>
<li><pre><code>vagrant plugin install vagrant-winnfsd
vagrant plugin install vagrant-vbguest
</code></pre>
</li>
</ul>
</li>
</ul>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-redis-4-0-bloom"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/11/28/redis-4-0-bloom/"
    >redis4.0以上版本开启bloomfilter插件的方法</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/11/28/redis-4-0-bloom/" class="article-date">
  <time datetime="2018-11-28T07:23:43.000Z" itemprop="datePublished">2018-11-28</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <ul>
<li><p>安装redis4.0</p>
<ul>
<li>参考<a target="_blank" rel="noopener" href="https://ken.io/note/centos7-redis4-setup">CentOS7 下 Redis4 安装与配置教程（Redis开机启动）</a></li>
<li>安装基础依赖<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo yum install -y gcc gcc-c++ make jemalloc-devel epel-release</span><br></pre></td></tr></table></figure></li>
<li>下载最新版redis并解压到指定目录, 然后编译和安装<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">wget http:&#x2F;&#x2F;download.redis.io&#x2F;releases&#x2F;redis-4.0.2.tar.gz</span><br><span class="line">sudo tar -zvxf redis-4.0.2.tar.gz -C &#x2F;usr&#x2F;</span><br><span class="line">#进入目录</span><br><span class="line">cd &#x2F;usr&#x2F;redis&#x2F;redis-4.0.2</span><br><span class="line">#编译&amp;安装</span><br><span class="line">sudo make &amp; make install</span><br><span class="line"></span><br><span class="line">sudo cp src&#x2F;redis-cli &#x2F;usr&#x2F;local&#x2F;bin&#x2F;（將redis-cli拷貝到bin下，讓redis-cli指令可以在任意目錄下直接使用）</span><br></pre></td></tr></table></figure></li>
<li>加载配置文件启动redis-server<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd &#x2F;usr&#x2F;redis&#x2F;redis-4.0.11</span><br><span class="line">redis-server redis.conf</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>安装Rebloom插件</p>
<ul>
<li>参考 <a target="_blank" rel="noopener" href="https://redislabs.com/blog/rebloom-bloom-filter-datatype-redis/">ReBloom – Bloom Filter Datatype for Redis</a></li>
<li>下载并编译<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git clone git:&#x2F;&#x2F;github.com&#x2F;RedisLabsModules&#x2F;rebloom</span><br><span class="line">$ cd rebloom</span><br><span class="line">$ make</span><br></pre></td></tr></table></figure></li>
<li>命令行加载rebloom插件,并且设定每个bloomfilter key的容量和错误率</li>
</ul>
  <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cd /usr/redis-4.0.11</span><br><span class="line">./src/redis-server redis.conf --loadmodule /usr/rebloom/rebloom.so INITIAL_SIZE 1000000 ERROR_RATE 0.0001</span><br><span class="line"><span class="meta">#</span><span class="bash"> 容量100万, 容错率万分之一, 占用空间是4m</span></span><br></pre></td></tr></table></figure></li>
<li><p>根据也无需求, 大于100万的bloomfilter key需要手动建立</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">BF.RESERVE 2018_ccgp 0.0001 28000000</span><br><span class="line">Memory Usage 2018_ccgp</span><br><span class="line"># (integer) 67108997 64M</span><br></pre></td></tr></table></figure></li>
<li><p>设置开机启动. <code>crontab -e</code> 输入</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@reboot &#x2F;usr&#x2F;redis-5.0.0&#x2F;src&#x2F;redis-server &#x2F;usr&#x2F;redis-5.0.0&#x2F;redis.conf --loadmodule &#x2F;usr&#x2F;rebloom&#x2F;rebloom.so INITIAL_SIZE 1000000 ERROR_RATE 0.0001</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
<li><p>阿里云服务器或者vangrant的centos镜像不需要设置防火墙的开放端口.</p>
</li>
</ul>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-win-terminus-md"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/11/20/win-terminus-md/"
    >terminus的安装和配置</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/11/20/win-terminus-md/" class="article-date">
  <time datetime="2018-11-20T05:31:35.000Z" itemprop="datePublished">2018-11-20</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <ul>
<li><p>下载git for windows并安装, 个人习惯安装时候不勾选git集成到右键菜单的的两个选项, 官方下载地址 <a target="_blank" rel="noopener" href="https://gitforwindows.org/">Git for windows</a></p>
</li>
<li><p>下载terminus并安装, 官方下载地址 <a target="_blank" rel="noopener" href="https://eugeny.github.io/terminus/">Terminus</a></p>
</li>
<li><p>设置, 单击左上角的齿轮</p>
<ul>
<li><p>shell设置页, shell选择为Git-Bash</p>
</li>
<li><p>terminal设置页, 右键设置为粘贴, 勾选 软件打开时自动开启一个终端,  勾选 阻止自动执行复制的到终端的内容, 勾选 选择时自动复制</p>
<p><img src="https://ww1.sinaimg.cn/large/007iUjdily1fxd5cjex8wj30p50j0ab8"></p>
</li>
<li><p>hotkeys设置页, 增加ctrl+v为粘贴快捷键. 这样, 最大的复合win的复制粘贴快捷键, 还是mac系统更合理, cmd+c是复制, cmd+v是粘贴. 与terminal的标准中断快捷键ctrl+c没有冲突</p>
</li>
<li><p>新建~/.bashrc文件, 并加入下面的内容,</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 按向上向下键自动匹配相应前缀的历史命令</span><br><span class="line">bind &#39;&quot;\e[A&quot;: history-search-backward&#39;</span><br><span class="line">bind &#39;&quot;\e[B&quot;: history-search-forward&#39;</span><br><span class="line">bind &#39;&quot;\e[C&quot;: forward-char&#39;</span><br><span class="line">bind &#39;&quot;\e[D&quot;: backward-char&#39;</span><br><span class="line"># 最大可能兼容win和linux的命令, 注意等号前后不能有空格</span><br><span class="line">alias ifconfig&#x3D;&#39;ipconfig&#39;</span><br><span class="line">alias ll&#x3D;&#39;ls -lah&#39;</span><br></pre></td></tr></table></figure>

<p>保存后, 重新打开terminus或者执行<code>source ~/.bashrc</code>即可</p>
<p>参考链接: <a target="_blank" rel="noopener" href="https://wiki.archlinux.org/index.php/Bash_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)">Bash (简体中文)</a></p>
</li>
</ul>
</li>
</ul>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-wsl-setting"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/08/13/wsl-setting/"
    >个人wsl设置</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/08/13/wsl-setting/" class="article-date">
  <time datetime="2018-08-13T11:14:05.000Z" itemprop="datePublished">2018-08-13</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <ul>
<li><h4 id="win10开启wsl并安装ubuntu"><a href="#win10开启wsl并安装ubuntu" class="headerlink" title="win10开启wsl并安装ubuntu"></a>win10开启wsl并安装ubuntu</h4><ul>
<li>win左下角搜索, 输入 <code>功能</code>, 找到 <code>启用或者关闭windows功能</code></li>
<li>找到<code>适用于Linux的Windows子功能</code>, 勾选</li>
<li>重启电脑</li>
<li>开始菜单MicroSoft Store, 搜索Ubuntu,找到ubuntu18.04安装</li>
<li>开始菜单,启动ubuntu18.04</li>
<li>等待一会后, 输入账号和密码</li>
<li>更改源, 换成清华源, 参考<a target="_blank" rel="noopener" href="https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/">Ubuntu 镜像使用帮助</a></li>
</ul>
</li>
</ul>
<ul>
<li><h4 id="系统更新"><a href="#系统更新" class="headerlink" title="系统更新"></a>系统更新</h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get upgrade</span><br></pre></td></tr></table></figure></li>
<li><h4 id="开启ssh"><a href="#开启ssh" class="headerlink" title="开启ssh"></a>开启ssh</h4><ul>
<li>安装<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get remove openssh-server</span><br><span class="line">sudo apt-get install openssh-server</span><br></pre></td></tr></table></figure></li>
<li>修改配置,<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vim &#x2F;etc&#x2F;ssh&#x2F;sshd_config</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Port 2222</span><br><span class="line">PasswordAuthentication yes</span><br></pre></td></tr></table></figure></li>
<li>启动<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service ssh --full-restart</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><h4 id="安装mysql"><a href="#安装mysql" class="headerlink" title="安装mysql"></a>安装mysql</h4><ul>
<li>安装</li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install mysql-server</span><br></pre></td></tr></table></figure>
<ul>
<li>配置, 这一项可能与下面添加root账号冲突.<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo service mysql start</span><br><span class="line">sudo mysql_secure_installation</span><br></pre></td></tr></table></figure></li>
<li>修改并添加root账户密码, 参考  <a target="_blank" rel="noopener" href="https://www.jianshu.com/p/4ca115648939">Ubuntu 18.04 安装记录 - 简书</a></li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sudo service mysql start</span><br><span class="line">sudo mysql -u root -p</span><br><span class="line">DROP USER &#39;root&#39;@&#39;localhost&#39;;</span><br><span class="line">CREATE USER &#39;root&#39;@&#39;%&#39; IDENTIFIED BY &#39;root&#39;;</span><br><span class="line">GRANT ALL PRIVILEGES ON *.* TO &#39;root&#39;@&#39;%&#39;;</span><br><span class="line">FLUSH PRIVILEGES;</span><br></pre></td></tr></table></figure>

<ul>
<li><p>开启远程访问, 参考, <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/28102425">mysql【一】：mysql在ubuntu上安装配置</a><br>修改 /etc/mysql/mysql.conf.d 下的mysqld.cnf，找到bind-address，把127.0.0.1 改为0.0.0.0</p>
</li>
<li><p>开启服务</p>
</li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service mysql start</span><br></pre></td></tr></table></figure></li>
<li><h4 id="安装redis"><a href="#安装redis" class="headerlink" title="安装redis"></a>安装redis</h4><ul>
<li>安装<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install redis-server</span><br></pre></td></tr></table></figure></li>
<li>配置远程访问<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vim &#x2F;etc&#x2F;redis&#x2F;redis.conf</span><br></pre></td></tr></table></figure>
找到并注释掉下面一行, 或者把127.0.0.1改成0.0.0.0<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># bind 127.0.0.1</span><br></pre></td></tr></table></figure></li>
<li>开启服务<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service redis-server start</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<ul>
<li><h4 id="中文支持和字体"><a href="#中文支持和字体" class="headerlink" title="中文支持和字体"></a>中文支持和字体</h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install language-pack-zh-hans</span><br><span class="line">sudo update-locale LANG&#x3D;zh_CN.UTF-8</span><br><span class="line">sudo mkdir &#x2F;usr&#x2F;share&#x2F;fonts</span><br><span class="line">sudo ln -s &#x2F;mnt&#x2F;c&#x2F;Windows&#x2F;Fonts &#x2F;usr&#x2F;share&#x2F;fonts&#x2F;windows</span><br><span class="line">sudo apt install fontconfig</span><br><span class="line">sudo fc-cache -fv</span><br></pre></td></tr></table></figure></li>
<li><h4 id="安装zsh"><a href="#安装zsh" class="headerlink" title="安装zsh"></a>安装zsh</h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install zsh</span><br><span class="line">sudo chsh -s $(which zsh)</span><br><span class="line">sh -c &quot;$(curl -fsSL https:&#x2F;&#x2F;raw.github.com&#x2F;robbyrussell&#x2F;oh-my-zsh&#x2F;master&#x2F;tools&#x2F;install.sh)&quot;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ul>
<ul>
<li><h4 id="启动zsh-bashrc"><a href="#启动zsh-bashrc" class="headerlink" title="启动zsh,  ~/.bashrc"></a>启动zsh,  ~/.bashrc</h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Launch Zsh</span><br><span class="line">if [ -t 1 ]; then</span><br><span class="line">exec zsh</span><br><span class="line">fi</span><br></pre></td></tr></table></figure></li>
<li><h4 id="开机启动mysql-redis-和ssh-在-zshrc加入"><a href="#开机启动mysql-redis-和ssh-在-zshrc加入" class="headerlink" title="开机启动mysql redis 和ssh, 在~/.zshrc加入"></a>开机启动mysql redis 和ssh, 在~/.zshrc加入</h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;检测开机启动项&quot;</span><br><span class="line">if [ ! -e &quot;&#x2F;var&#x2F;run&#x2F;sshd.pid&quot; ]; then</span><br><span class="line">    echo &#39;启动sshd&#39;</span><br><span class="line">    sudo service ssh start</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">if test $( pgrep -f mysql | wc -l ) -lt 1</span><br><span class="line">    then</span><br><span class="line">    echo &quot;启动mysql&quot;</span><br><span class="line">    sudo service mysql start</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">if test $( pgrep -f redis | wc -l ) -lt 1</span><br><span class="line">    then</span><br><span class="line">    echo &quot;启动redis&quot;</span><br><span class="line">    sudo service redis-server start</span><br><span class="line">fi</span><br></pre></td></tr></table></figure></li>
</ul>
<ul>
<li><h4 id="启动显示-zshrc"><a href="#启动显示-zshrc" class="headerlink" title="启动显示 ~/.zshrc"></a>启动显示 ~/.zshrc</h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">umask 0022</span><br><span class="line">export DISPLAY&#x3D;localhost:0.0</span><br></pre></td></tr></table></figure></li>
<li><h4 id="修改wsl里面查看windows磁盘文件的颜色1-参考"><a href="#修改wsl里面查看windows磁盘文件的颜色1-参考" class="headerlink" title="修改wsl里面查看windows磁盘文件的颜色1, 参考"></a>修改wsl里面查看windows磁盘文件的颜色1, 参考</h4><p>  [在WSL环境下修改文件夹的颜色] (<a target="_blank" rel="noopener" href="https://blog.royink.li/post/ls_color_in_wsl">https://blog.royink.li/post/ls_color_in_wsl</a>)<br>  <a target="_blank" rel="noopener" href="https://github.com/trapd00r/LS_COLORS/blob/master/README.markdown">LS_COLORS</a></p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dircolors -p &gt; $HOME&#x2F;.dircolors</span><br><span class="line">vim $HOME&#x2F;.dircolors</span><br></pre></td></tr></table></figure>
<p>  将<br>  STICKY_OTHER_WRITABLE 后面的数字改成02;32<br>  OTHER_WRITABLE 后面的数字改成01;34</p>
<p>  然后在<code>$HOME/.bashrc</code>(如果用zsh, <code>$HOME/.zshrc</code>)后面添加</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eval $(dircolors -b $HOME&#x2F;.dircolors)</span><br></pre></td></tr></table></figure></li>
<li><h4 id="修改wsl里面查看windows磁盘文件的颜色2-参考Quick-rundown-on-my-current-setup-on-the-Windows-Subsystem-for-Linux"><a href="#修改wsl里面查看windows磁盘文件的颜色2-参考Quick-rundown-on-my-current-setup-on-the-Windows-Subsystem-for-Linux" class="headerlink" title="修改wsl里面查看windows磁盘文件的颜色2, 参考Quick rundown on my current setup on the Windows Subsystem for Linux."></a>修改wsl里面查看windows磁盘文件的颜色2, 参考<a target="_blank" rel="noopener" href="https://github.com/lloydstubber/my-wsl-setup">Quick rundown on my current setup on the Windows Subsystem for Linux.</a></h4>  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#Change ls colours</span><br><span class="line">LS_COLORS&#x3D;&quot;ow&#x3D;01;36;40&quot; &amp;&amp; export LS_COLORS</span><br><span class="line"></span><br><span class="line">#make cd use the ls colours</span><br><span class="line">zstyle &#39;:completion:*&#39; list-colors &quot;$&#123;(@s.:.)LS_COLORS&#125;&quot;</span><br><span class="line">autoload -Uz compinit</span><br><span class="line">compinit</span><br></pre></td></tr></table></figure></li>
<li><h4 id="安装anaconda"><a href="#安装anaconda" class="headerlink" title="安装anaconda"></a>安装anaconda</h4><ul>
<li>安装用清华的下载, <a target="_blank" rel="noopener" href="https://mirror.tuna.tsinghua.edu.cn/help/anaconda/">Anaconda | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror</a></li>
<li>根据清华源的教程,设置源</li>
<li>把path加入~/.zshrc</li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">export PATH&#x3D;&#x2F;home&#x2F;xin&#x2F;anaconda3&#x2F;bin:$PATH</span><br></pre></td></tr></table></figure>

<ul>
<li>更改权限</li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo chown -R xin:xin &#x2F;home&#x2F;xin&#x2F;anaconda3</span><br></pre></td></tr></table></figure>

<p>  或者</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo chmod 777 -R &#x2F;home&#x2F;xin&#x2F;anaconda3</span><br></pre></td></tr></table></figure>
<ul>
<li>修改pip源</li>
</ul>
</li>
<li><h4 id="安装jdk"><a href="#安装jdk" class="headerlink" title="安装jdk"></a>安装jdk</h4><ul>
<li>官网下载相应的jdk, 解压并拷贝到/opt目录下</li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo cp jdk-8u171-linux-x64.tar.gz &#x2F;opt</span><br><span class="line">sudo tar -zxvf jdk-8u171-linux-x64.tar.gz</span><br></pre></td></tr></table></figure>

<ul>
<li>配置path, 打开~/.zshrc</li>
</ul>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">export JAVA_HOME&#x3D;&#x2F;opt&#x2F;jdk1.8.0_171</span><br><span class="line">export PATH&#x3D;$JAVA_HOME&#x2F;bin:$PATH</span><br></pre></td></tr></table></figure></li>
<li><h4 id="安装pycharm和idea"><a href="#安装pycharm和idea" class="headerlink" title="安装pycharm和idea"></a>安装pycharm和idea</h4><p>  官网下载, 拷贝到/opt目录里面解压缩,类似于jdk,<br>  运行</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sh &#x2F;opt&#x2F;pycharm-2018.2&#x2F;bin&#x2F;pycharm.sh &amp;</span><br></pre></td></tr></table></figure></li>
<li><h4 id="安装maven"><a href="#安装maven" class="headerlink" title="安装maven"></a>安装maven</h4><ul>
<li>下载, 设置类似于jdk</li>
<li>设置阿里云源</li>
</ul>
</li>
<li><h4 id="安装多个wsl的linux-修改默认版本"><a href="#安装多个wsl的linux-修改默认版本" class="headerlink" title="安装多个wsl的linux, 修改默认版本"></a>安装多个wsl的linux, 修改默认版本</h4><p>  开始菜单右键, 选择管理员模式打开powershell</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">wslconfig &#x2F;list # 列出安装的wsl不同linux版本</span><br><span class="line">wslconfig &#x2F;s ubuntu-18.04 # 设置默认版本</span><br></pre></td></tr></table></figure></li>
<li><h4 id="下载并安装vcxsrv-VcXsrv-Windows-X-Server"><a href="#下载并安装vcxsrv-VcXsrv-Windows-X-Server" class="headerlink" title="下载并安装vcxsrv, VcXsrv Windows X Server,"></a>下载并安装vcxsrv, <a target="_blank" rel="noopener" href="https://sourceforge.net/projects/vcxsrv/">VcXsrv Windows X Server</a>,</h4><p>双击桌面xserver图标启动, 在Clipboard设置界面去掉 Clickboard勾选和Primary Selection. 这样可以屏蔽pycharm里面的select and copy(选择并拷贝).</p>
<p><img src="https://ww3.sinaimg.cn/large/005YhI8igy1fu886ttxelj30if0dkt97"></p>
<p>参考:</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://sourceforge.net/p/vcxsrv/discussion/986201/thread/8dc32d4d/">copy on select seems to be enable…somewhere</a></li>
<li><a target="_blank" rel="noopener" href="https://superuser.com/questions/440128/xming-clipboard-only-works-one-way">Xming clipboard only works one way</a></li>
</ul>
</li>
</ul>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E8%BD%AF%E4%BB%B6-windows-linux/" rel="tag">软件, windows, linux</a></li></ul>

    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-handle-some-web-font-crawl"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/04/14/handle-some-web-font-crawl/"
    >某8网站字体加密爬虫的处理方法</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/04/14/handle-some-web-font-crawl/" class="article-date">
  <time datetime="2018-04-14T08:48:38.000Z" itemprop="datePublished">2018-04-14</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p><img src="https://ww1.sinaimg.cn/large/7293e3b7gy1fqbijxv90kj217a0f4go4.jpg"></p>
<p>某8网站的一些数据在浏览器里面显示是正常的, 但是渲染前和渲染后的html源码都看不到字体, 渲染前看到的是16进制的4位字符, 渲染后看到的是一些方块.</p>
<p>搜索找到猫眼和汽车之家的解决方法, 某8网站比这些都复杂, 经过多次尝试得到解决.</p>
<p>首先在html源码里面找到woff字体的base4编码, 保存成”font.woff”字体文件, 用fontTools库将这个字体文件存储为”font.xml”文件.</p>
<p><img src="https://ww1.sinaimg.cn/large/7293e3b7gy1fqbiw8ot0zj20pu0e3tbp.jpg"></p>
<p>然后在xml里面找到<code>TTGlyph</code>字段, 这个字段下面的 子字段都是用来画字符(包括中英文数字)的坐标. 同一个字符的坐标是一样的. 解析xml, 然后把这些坐标的属性字典按顺序都存到一个list里面, 然后序列化成json(加sort_keys=True参数)字符串. 用这个字符串当key, value是实际的字符, 存成一个constant_dict. 每次遇到新网页, 取出这个字符串, 然后根据字符串从constant_dict获取实际的字符.</p>
<p>每次获取font里面坐标list字符串的代码:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># font_decryption.py</span></span><br><span class="line"><span class="keyword">from</span> fontTools.ttLib <span class="keyword">import</span> TTFont</span><br><span class="line"><span class="keyword">from</span> lxml <span class="keyword">import</span> etree</span><br><span class="line"><span class="keyword">from</span> io <span class="keyword">import</span> BytesIO</span><br><span class="line"><span class="keyword">import</span> base64</span><br><span class="line"><span class="keyword">import</span> config</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> pub.common.error <span class="keyword">as</span> error</span><br><span class="line"></span><br><span class="line">_xml_file_path = os.path.join(config.temp_file_path, <span class="string">&quot;tongcheng58.xml&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">make_font_file</span>(<span class="params">base64_string: <span class="built_in">str</span></span>):</span></span><br><span class="line">    bin_data = base64.decodebytes(base64_string.encode())</span><br><span class="line">    <span class="keyword">return</span> bin_data</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">convert_font_to_xml</span>(<span class="params">bin_data</span>):</span></span><br><span class="line">    font = TTFont(BytesIO(bin_data))</span><br><span class="line">    font.saveXML(_xml_file_path)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">parse_xml</span>():</span></span><br><span class="line">    xml = etree.parse(_xml_file_path)</span><br><span class="line">    root = xml.getroot()</span><br><span class="line">    font_dict = &#123;&#125;</span><br><span class="line">    all_data = root.xpath(<span class="string">&#x27;//glyf/TTGlyph&#x27;</span>)</span><br><span class="line">    <span class="keyword">for</span> index, data <span class="keyword">in</span> <span class="built_in">enumerate</span>(all_data):</span><br><span class="line">        font_key = data.attrib.get(<span class="string">&#x27;name&#x27;</span>)[<span class="number">3</span>:].lower()</span><br><span class="line">        contour_list = []</span><br><span class="line">        <span class="keyword">if</span> index == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        <span class="keyword">for</span> contour <span class="keyword">in</span> data:</span><br><span class="line">            <span class="keyword">for</span> pt <span class="keyword">in</span> contour:</span><br><span class="line">                contour_list.append(<span class="built_in">dict</span>(pt.attrib))</span><br><span class="line">        font_dict[font_key] = json.dumps(contour_list, sort_keys=<span class="literal">True</span>)</span><br><span class="line">    <span class="keyword">return</span> font_dict</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">make_path</span>():</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> os.path.isdir(config.temp_file_path):</span><br><span class="line">        os.makedirs(config.temp_file_path)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_font_dict</span>(<span class="params">base64_string</span>):</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        make_path()</span><br><span class="line">        bin_data = make_font_file(base64_string)</span><br><span class="line">        convert_font_to_xml(bin_data)</span><br><span class="line">        font_dict = parse_xml()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">return</span> (error.ERROR_UNKNOWN_RESUME_CONTENT, <span class="string">&#x27;cannot_get_font, err=[&#123;&#125;]&#x27;</span>.<span class="built_in">format</span>(<span class="built_in">str</span>(e))), <span class="literal">None</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">None</span>, font_dict</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>调用</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">decrypt_font</span>(<span class="params">text, font_dict</span>):</span></span><br><span class="line">    decryption_text = <span class="string">&quot;&quot;</span></span><br><span class="line">    <span class="keyword">for</span> alpha <span class="keyword">in</span> text:</span><br><span class="line">        hex_alpha = alpha.encode(<span class="string">&#x27;unicode_escape&#x27;</span>).decode()[<span class="number">2</span>:]</span><br><span class="line">        <span class="keyword">if</span> hex_alpha <span class="keyword">in</span> font_dict:</span><br><span class="line">            item_text = decryption_font_dict.get(font_dict[hex_alpha])</span><br><span class="line">            <span class="keyword">if</span> item_text <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">                _logger.error(<span class="string">&quot;op=[DecryptFont], err=&#123;&#125;&quot;</span>.<span class="built_in">format</span>(<span class="string">&quot;decryption_font_dict_have_no_this_font&quot;</span>))</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            item_text = alpha</span><br><span class="line">        decryption_text += item_text</span><br><span class="line">    <span class="keyword">return</span> decryption_text</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">parse</span>(<span class="params">html: <span class="built_in">str</span>, request: ParseRequest</span>):</span></span><br><span class="line">    user_info_dict = &#123;&#125;</span><br><span class="line">    <span class="comment"># print(html)</span></span><br><span class="line">    base64_string = html.split(<span class="string">&quot;base64,&quot;</span>)[<span class="number">1</span>].split(<span class="string">&#x27;)&#x27;</span>)[<span class="number">0</span>].strip()</span><br><span class="line">    err, font_dict = get_font_dict(base64_string)</span><br><span class="line">    <span class="keyword">if</span> err <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">return</span> err, <span class="literal">None</span></span><br><span class="line">    html = decrypt_font(html, font_dict)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    html = <span class="built_in">open</span>(file_name, <span class="string">&quot;r&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>).read()</span><br><span class="line"></span><br><span class="line">    parse(html)</span><br></pre></td></tr></table></figure>


<p>参考:<br><a target="_blank" rel="noopener" href="https://www.jianshu.com/p/5400bbc8b634">解析某电影和某招聘网站的web-font自定义字体</a><br><a target="_blank" rel="noopener" href="http://www.atbrask.dk/?cat=11">The ramblings of atbrask</a><br><a target="_blank" rel="noopener" href="https://blog.csdn.net/xyq046463/article/details/58606657">python3 汉字转十六进制unicode</a></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/python/" rel="tag">python</a></li></ul>

    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-java-python-s-map"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/04/14/java-python-s-map/"
    >python和java的类当做map的键</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/04/14/java-python-s-map/" class="article-date">
  <time datetime="2018-04-13T16:49:51.000Z" itemprop="datePublished">2018-04-14</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>python和java的类当做dict(map)键时候, 如果不覆写hash()和equals方法, 默认使用地址值的hash值存储到map里面, 两个同样属性的类, 虽然内容是一样的,但是地址不一样, 会被当做两个map的key存在. </p>
<p>两个内容相同,但是地址不同的<strong>字符串</strong>当做key的时候, map存储一个key. </p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">string_dict = &#123;&#125;</span><br><span class="line">string1 = <span class="string">&quot;data&quot;</span></span><br><span class="line">string2 = <span class="string">&quot;data&quot;</span></span><br><span class="line">string_dict[string1] = <span class="string">&quot;value1&quot;</span></span><br><span class="line">string_dict[string2] = <span class="string">&quot;value2&quot;</span></span><br><span class="line">print(string_dict)</span><br><span class="line">&#123;<span class="string">&#x27;data&#x27;</span>: <span class="string">&#x27;value2&#x27;</span>&#125;</span><br></pre></td></tr></table></figure>

<p>这样的意义在于在A函数定义了一个dict(map), B函数用这个dict获取key对应值的时候, 虽然这两个key的类的地址一般不会一致, 但是A和B函数的两个类key内容一样, 就可以获取到同一个value.</p>
<p>类需要覆写hash()和equals方法才能实现同样的功能</p>
<h3 id="python测试代码"><a href="#python测试代码" class="headerlink" title="python测试代码"></a>python测试代码</h3><p>覆写了hash()和equals方法</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ClassName</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    <span class="string">&quot;&quot;&quot;docstring for ClassName&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self, arg</span>):</span></span><br><span class="line">        self.data = arg</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__eq__</span>(<span class="params">self, another</span>):</span></span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">hasattr</span>(another, <span class="string">&#x27;data&#x27;</span>) <span class="keyword">and</span> self.data == another.data</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__hash__</span>(<span class="params">self</span>):</span></span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">hash</span>(self.data)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__lt__</span>(<span class="params">self, another</span>):</span></span><br><span class="line">        <span class="keyword">return</span> self.data - another.data</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func_a</span>() -&gt; dict:</span></span><br><span class="line">    class_a = ClassName(<span class="number">1234</span>)</span><br><span class="line">    print(<span class="string">&quot;class_a address_id=&quot;</span>, <span class="built_in">id</span>(class_a))</span><br><span class="line">    class_dict = &#123;class_a: <span class="string">&quot;value&quot;</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> class_dict</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func_b</span>(<span class="params">class_dict: <span class="built_in">dict</span></span>):</span></span><br><span class="line">    class_b = ClassName(<span class="number">1234</span>)</span><br><span class="line">    print(<span class="string">&quot;class_b address_id=&quot;</span>, <span class="built_in">id</span>(class_b))</span><br><span class="line">    value = class_dict.get(class_b)</span><br><span class="line">    print(value)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span>():</span></span><br><span class="line">    class_dict = func_a()</span><br><span class="line">    func_b(class_dict)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure>

<p>输出是:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">class_a address_id&#x3D; 4492965144</span><br><span class="line">class_b address_id&#x3D; 4492965200</span><br><span class="line">value</span><br></pre></td></tr></table></figure>

<h3 id="java相应测试代码"><a href="#java相应测试代码" class="headerlink" title="java相应测试代码:"></a>java相应测试代码:</h3><p>没有覆写hash()和equals方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">用lombok注解实现构造方法方法</span><br><span class="line"><span class="meta">@Setter</span></span><br><span class="line"><span class="meta">@Getter</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Student</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">App</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Map&lt;Student, String&gt; map =getStudentMap();</span><br><span class="line">        printStudent(map);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">private</span> Map&lt;Student, String&gt; <span class="title">getStudentMap</span><span class="params">()</span></span>&#123;</span><br><span class="line">        Map&lt;Student, String&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;(<span class="number">16</span>);</span><br><span class="line">        Student studentA = <span class="keyword">new</span> Student(<span class="string">&quot;xin&quot;</span>, <span class="number">20</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;studentA&#x27;s address = &quot;</span> + studentA);</span><br><span class="line">        map.put(studentA, <span class="string">&quot;value&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> map;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title">printStudent</span><span class="params">(Map&lt;Student, String&gt; map)</span></span>&#123;</span><br><span class="line">        Student studentB = <span class="keyword">new</span> Student(<span class="string">&quot;xin&quot;</span>, <span class="number">20</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;studentB&#x27;s address = &quot;</span> + studentB);</span><br><span class="line">        System.out.println(<span class="string">&quot;两个函数是否相等: &quot;</span> + Objects.equals(studentB, map.keySet().toArray()[<span class="number">0</span>]));</span><br><span class="line">        System.out.println(<span class="string">&quot;从map中获取到的值是:&quot;</span> + map.get(studentB));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>输出是: </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">studentA&#39;s address &#x3D; com.example.demo002.zhihu.Student@548c4f57</span><br><span class="line">studentB&#39;s address &#x3D; com.example.demo002.zhihu.Student@1218025c</span><br><span class="line">两个函数是否相等: false</span><br><span class="line">从map中获取到的值是:null</span><br></pre></td></tr></table></figure>


<p>参考地址:<br><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000002655085">Java 用自定义类型作为HashMap的键</a><br><a target="_blank" rel="noopener" href="https://stackoverflow.com/questions/5221236/python-my-classes-as-dict-keys-how">python: my classes as dict keys. how?</a></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/python-java/" rel="tag">python, java</a></li></ul>

    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-javaProxy"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/03/19/javaProxy/"
    >jdk动态代理和Cglib代理笔记</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/03/19/javaProxy/" class="article-date">
  <time datetime="2018-03-19T08:36:53.000Z" itemprop="datePublished">2018-03-19</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a>动态代理</h2><p><a target="_blank" rel="noopener" href="https://www.imooc.com/video/4704">https://www.imooc.com/video/4704</a> 这个视频的笔记</p>
<p><img src="https://ww1.sinaimg.cn/large/7293e3b7ly1fph53nxdxdj21gk0mmgoj.jpg"></p>
<p>java动态代理类位于java.lang.reflect包下, 一般主要是设计到一下两个类:</p>
<ul>
<li><p>Interface InvocationHandler: 该接口种仅仅定义了一个方法<br><code>public object invoke(Object obj, Method method, Object[] args)</code><br>在实际使用时, 第一个参数obj一般指代理类, method只被代理的方法, args为该方法的参数数组.<br>这个抽象方法在代理类种动态实现.</p>
</li>
<li><p>Proxy: 该类是动态代理类<br><code>Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)</code>, 返回代理类的一个实例, 返回后的代理类可以被代理类使用(可使用被代理类种在接口中声明过的方法)</p>
</li>
<li><p>描述<br>所谓动态代理是这样一中class, 它在运行时生成的class(没有.java文件),<br>该class实现了被代理对象的一组interface, 使用动态代理类是, 必须实现InvocationHandler接口</p>
</li>
<li><p>步骤</p>
<ul>
<li>1: 创建一个实现接口 InvocationHandler的类, 必须实现invoke方法, 在被代理类的方法前后添加要实现的功能</li>
<li>2: 创建被代理类以及接口</li>
<li>3: 调用Proxy类的静态方法, 创建一个代理类<br>Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)</li>
<li>通过代理调用方法</li>
</ul>
</li>
</ul>
<p>接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Moveable</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">movie</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>被代理的类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span> <span class="keyword">implements</span> <span class="title">Moveable</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">movie</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">5</span>));</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>动态代理</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现InvocationHandler接口, 复写invoke, 在被代理对象方法前后增加新的功能, 返回被代理对象的返回值</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TimeHandler</span> <span class="keyword">implements</span> <span class="title">InvocationHandler</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Object target;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">TimeHandler</span><span class="params">(Object target)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.target = target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> proxy 被代理的对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> method 被代理对象的方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> args 被代理对象方法的参数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 被代理Object对象 方法的返回值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> Throwable</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">long</span> start = System.currentTimeMillis();</span><br><span class="line">        System.out.println(<span class="string">&quot;汽车开始行驶&quot;</span>);</span><br><span class="line">        method.invoke(target);</span><br><span class="line">        <span class="keyword">long</span> end = System.currentTimeMillis();</span><br><span class="line">        System.out.println(<span class="string">&quot;汽车终止行驶!&quot;</span>);</span><br><span class="line">        System.out.println((end - start)/ <span class="number">1000.0</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>代理类的测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * jdk动态代理测试类</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        Car car = <span class="keyword">new</span> Car();</span><br><span class="line">        InvocationHandler handler = <span class="keyword">new</span> TimeHandler(car);</span><br><span class="line">        Class&lt;?&gt; carClass = car.getClass();</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * loader: 类加载器</span></span><br><span class="line"><span class="comment">         * interfaces 类实现的接口</span></span><br><span class="line"><span class="comment">         * h InvocationHandler</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        Moveable moveable = (Moveable) Proxy.newProxyInstance(</span><br><span class="line">                carClass.getClassLoader(),</span><br><span class="line">                carClass.getInterfaces(),</span><br><span class="line">                handler);</span><br><span class="line">        moveable.movie();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Cglib代理"><a href="#Cglib代理" class="headerlink" title="Cglib代理"></a>Cglib代理</h2><p>也叫做子类代理. 用被代理类的子类对象增加功能来实现的.</p>
<p>被代理类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Train</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">move</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;火车行驶中...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建cglib代理类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> net.sf.cglib.proxy.Enhancer;</span><br><span class="line"><span class="keyword">import</span> net.sf.cglib.proxy.MethodInterceptor;</span><br><span class="line"><span class="keyword">import</span> net.sf.cglib.proxy.MethodProxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CglibProxy</span> <span class="keyword">implements</span> <span class="title">MethodInterceptor</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Enhancer enhancer = <span class="keyword">new</span> Enhancer();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">getProxy</span><span class="params">(Class cls)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 设置创建子类(代理类)的类(被代理的类)</span></span><br><span class="line">        enhancer.setSuperclass(cls);</span><br><span class="line">        enhancer.setCallback(<span class="keyword">this</span>);</span><br><span class="line">        <span class="keyword">return</span> enhancer.create();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * cglib通过继承父类方法来实现代理</span></span><br><span class="line"><span class="comment">     * 拦截所有目标类方法的调用</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o           目标类的实例</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> method      目标方法的反射对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> objects     目标方法的参数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> methodProxy 代理类的实例</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 目标类方法的返回值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">intercept</span><span class="params">(Object o, Method method, Object[] objects, MethodProxy methodProxy)</span></span></span><br><span class="line"><span class="function">            <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;日志开始记录&quot;</span>);</span><br><span class="line">        <span class="comment">// 代理类调用父类的方法</span></span><br><span class="line">        methodProxy.invokeSuper(o, objects);</span><br><span class="line">        System.out.println(<span class="string">&quot;日志结束...&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试cglib代理</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        CglibProxy proxy = <span class="keyword">new</span> CglibProxy();</span><br><span class="line">        Train train = (Train) proxy.getProxy(Train.class);</span><br><span class="line">        train.move();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>输入结果, 在被代理类功能前后都增加了新功能.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">日志开始记录</span><br><span class="line">火车行驶中...</span><br><span class="line">日志结束...</span><br></pre></td></tr></table></figure>






 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/" rel="tag">java</a></li></ul>

    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-javaAnnotation"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/03/19/javaAnnotation/"
    >java注解笔记</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/03/19/javaAnnotation/" class="article-date">
  <time datetime="2018-03-19T06:30:46.000Z" itemprop="datePublished">2018-03-19</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <ol>
<li><p>注解的作用</p>
<ul>
<li>读懂别人写的代码, 特别是框架的相关代码</li>
<li>让编程更加简洁, 代码更清晰</li>
<li>会写自定义注解 提升自己的能力</li>
</ul>
</li>
<li><p>定义:<br> java提供了一中原程序中的元素关联任何信息和任何元数据的途径和方法.</p>
</li>
<li><p>常见注解</p>
<ul>
<li>jdk自带<ul>
<li>@Override   表示当前方法覆盖了父类的方法</li>
<li>@Deprecation   表示方法已经过时,方法上有横线，使用时会有警告</li>
<li>@SuppviseWarnings 表示关闭一些警告信息(通知java编译器忽略特定的编译警告), 比如使用过期的(即用@Deprecation标识的方法)时, 会有编译器警告, 加上这个注解可以消除这个警告.</li>
</ul>
</li>
<li>Spring 注解<ul>
<li>@Autowired spring 自动装配</li>
<li>@Qualifier(“JavaBea”) 配合 @Autowired 实现自动装配</li>
<li>@Resource(name=”JavaBean”) spring 自动装配, 不写参数直接装配同类型的类</li>
<li>@PostConstruct 类初始化的方法</li>
<li>@PreDestroy 类销毁的方法</li>
<li>@Component 表名类为 JavaBean</li>
<li>@Scope(“prototype” ) 指定Bean的作用范围, prototype为每次都重新实例化</li>
<li>@Repository 与 @Component 作用相同, 常用于数据持久层</li>
<li>@Service 与 @Component 作用相同, 常用于业务逻辑层</li>
<li>@Controller 与 @Component 作用相同, 常用于控制表现层 </li>
</ul>
</li>
<li>Mybatis 注解<ul>
<li>@Select</li>
<li>@Option</li>
</ul>
</li>
<li>Autowired 举例<ol>
<li>用类实习创建类的实例 <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UerManagerImpl</span> <span class="keyword">implements</span> <span class="title">UserManager</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> UserDao userDao;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUserDao</span><span class="params">(UserDao userDao)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.userDao = userDao;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<ol start="2">
<li>用配置文件实现创建类实例 <figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;bean id=<span class="string">&quot;UerManagerImpl&quot;</span> <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;xxx.service.UserManager&quot;</span>&gt;</span><br><span class="line">    &lt;property name =<span class="string">&quot;userDao&quot;</span> ref=<span class="string">&quot;userDao&quot;</span> /&gt;</span><br><span class="line">&lt;/bean&gt;</span><br><span class="line">&lt;bean id=<span class="string">&quot;userDao&quot;</span> <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;xxx.UerManagerImpl&quot;</span></span><br><span class="line">    &lt;property name =<span class="string">&quot;sessionFactory&quot;</span> ref=<span class="string">&quot;mySessionFactory&quot;</span> /&gt;</span><br><span class="line">&lt;/bean&gt;</span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<ol start="3">
<li><p>用注解实现类实例的创建</p>
 <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UerManagerImpl</span> <span class="keyword">implements</span> <span class="title">UserManager</span></span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserDao userDao;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
</ul>
</li>
</ol>
<ul>
<li><p>注解分类</p>
<ul>
<li>按照运行机制分类<ul>
<li>源码注解 : 注解只在源码里面存在, 编译生成.class文件时就不存在了. (这里的源码指自己编写的java代码.)</li>
<li>编译时注解: 注解在源码和.class文件中存在, jdk自带的3个注解都属于编译时注解</li>
<li>运行时注解: 在运行阶段还起作用, 甚至影响运行逻辑的注解. spring的  @Autowired 属于运行时注解</li>
</ul>
</li>
<li>注解来源:<ul>
<li>jdk注解</li>
<li>第三方注解</li>
<li>自定义注解</li>
</ul>
</li>
<li>元注解:<ul>
<li>注解的注解  </li>
</ul>
</li>
</ul>
</li>
<li><p>自定义注解</p>
<ol>
<li><p>注解定义</p>
 <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">import java.lang.annotation.Documented;</span><br><span class="line">import java.lang.annotation.ElementType;</span><br><span class="line">import java.lang.annotation.Inherited;</span><br><span class="line">import java.lang.annotation.Retention;</span><br><span class="line">import java.lang.annotation.RetentionPolicy;</span><br><span class="line">import java.lang.annotation.Target;</span><br><span class="line"></span><br><span class="line">&#x2F;**</span><br><span class="line"> * 下面4个被称为元注解,</span><br><span class="line"> *&#x2F;</span><br><span class="line"></span><br><span class="line">&#x2F;&#x2F; @Target: 注解的作用域, 包括(CONSTRUCTOR(构造方法), FIELD(类属性), LOCAL_VARIABLE(局部变量),</span><br><span class="line">&#x2F;&#x2F; METHOD(方法), PACKAGE(包), PARAMETER(参数), TYPE(类, 接口))</span><br><span class="line"></span><br><span class="line">@Target(&#123;ElementType.METHOD, ElementType.TYPE&#125;)</span><br><span class="line"></span><br><span class="line">&#x2F;&#x2F; @Retention: 注解的生命周期, 包括(SOURCE, CLASS, RUNTIME)</span><br><span class="line">&#x2F;&#x2F; SOURCE: 只在源码种显示, 编译时丢弃,</span><br><span class="line">&#x2F;&#x2F; CLASS 编译时会记录到class中, 运行时忽略</span><br><span class="line">&#x2F;&#x2F; RUNTIME 运行时存在, 可以通过反射读取</span><br><span class="line">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="line"></span><br><span class="line">&#x2F;&#x2F; @Inherited 允许子类继承父类的类注解, 父类的方法注解无法继承</span><br><span class="line">&#x2F;&#x2F; 注意, 注解定义到接口上, 实现的时候解析是无效的</span><br><span class="line">@Inherited</span><br><span class="line"></span><br><span class="line">&#x2F;&#x2F; @Documented 生成javadoc时候回包含注解, 属于标识注解</span><br><span class="line">@Documented</span><br><span class="line"></span><br><span class="line">&#x2F;&#x2F;使用 @interface 关键字定义注解</span><br><span class="line">public @interface Description &#123;</span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 成员类型是受限的, 合法的类型包括原始类型及String, Class, Annotation, Enumeration</span><br><span class="line">     *</span><br><span class="line">     * 如果注解只有一个成员, 则成员名必须取名为value(), 在使用时可以忽略程一鸣和赋值号(&#x3D;)</span><br><span class="line">     *</span><br><span class="line">     * 注解类可以没有成员, 没有成员的注解称为标识注解</span><br><span class="line">     *&#x2F;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F;成员以无参无异常方式声明,  成员就是注解里面元素定义的名词</span><br><span class="line">    String desc();</span><br><span class="line"></span><br><span class="line">    String author();</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 可以用default为成员制定一个默认值</span><br><span class="line">    int age() default 18;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>注解使用</p>
 <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * 使用自定义注解的语法:</span><br><span class="line"> *</span><br><span class="line"> * @&lt;注解名&gt;(&lt;成员名1&gt;&#x3D;&lt;成员值1&gt;, &lt;成员名1&gt;&#x3D;&lt;成员值1&gt;, ...)</span><br><span class="line"> *&#x2F;</span><br><span class="line"></span><br><span class="line">@Description(desc &#x3D; &quot;描述信息, 注解在类上&quot;, author &#x3D; &quot;姓名&quot;)</span><br><span class="line">public class CustomAnnotation &#123;</span><br><span class="line">    public String string;</span><br><span class="line"></span><br><span class="line">    @Description(desc &#x3D; &quot;描述信息, 注解在方法上&quot;, author &#x3D; &quot;作者名&quot;, age &#x3D; 30)</span><br><span class="line">    public String eyeColor() &#123;</span><br><span class="line">        return &quot;black&quot;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>解析注解 : 通过反射获取类 函数 或者 属性上 运行时 注解信息, 从而实现动态控制程序运行的逻辑.</p>
 <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">import java.lang.annotation.Annotation;</span><br><span class="line">import java.lang.reflect.Method;</span><br><span class="line">import java.util.Arrays;</span><br><span class="line"></span><br><span class="line">&#x2F;**</span><br><span class="line"> * @author: 个人姓名</span><br><span class="line"> * @date: 2018&#x2F;3&#x2F;18 下午10:15</span><br><span class="line"> * @className: TestAnnotation</span><br><span class="line"> * @version: 1.0.0</span><br><span class="line"> * @description:</span><br><span class="line"> *&#x2F;</span><br><span class="line">public class TestAnnotation &#123;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 能运行时候解析到结果的注解都是 运行时注解, 一定要用@Retention(RetentionPolicy.RUNTIME)</span><br><span class="line">     *&#x2F;</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args) throws ClassNotFoundException &#123;</span><br><span class="line">        &#x2F;&#x2F;1: 使用类加载器加载类</span><br><span class="line">        Class cls &#x3D; Class.forName(&quot;com.linkzp.jdkproxy.CustomAnnotation&quot;);</span><br><span class="line">        &#x2F;&#x2F; 2: 找到类上的注解,</span><br><span class="line">        System.out.println(Arrays.toString(cls.getAnnotationsByType(Description.class)));</span><br><span class="line">        boolean isExist &#x3D; cls.isAnnotationPresent(Description.class);</span><br><span class="line">        if (isExist) &#123;</span><br><span class="line">            &#x2F;&#x2F; 3: 拿到注解实例</span><br><span class="line"></span><br><span class="line">            Description description &#x3D; (Description) cls.getAnnotation(Description.class);</span><br><span class="line">            System.out.println(description.author());</span><br><span class="line">            System.out.println(description.desc());</span><br><span class="line">            System.out.println(description.age());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        &#x2F;&#x2F; 4: 找到方法的注解</span><br><span class="line">        Method[] methods &#x3D; cls.getMethods();</span><br><span class="line"></span><br><span class="line">        for (Method method : methods) &#123;</span><br><span class="line">            boolean isMethodAnnotation &#x3D; method.isAnnotationPresent(Description.class);</span><br><span class="line">            if (isMethodAnnotation) &#123;</span><br><span class="line">                Description methodDescription &#x3D; method.getAnnotation(Description.class);</span><br><span class="line">                System.out.println(methodDescription.author());</span><br><span class="line">                System.out.println(methodDescription.desc());</span><br><span class="line">                System.out.println(methodDescription.age());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        &#x2F;&#x2F; 5: 方法注解解析的另外一种解析方法</span><br><span class="line"></span><br><span class="line">        for (Method method : methods) &#123;</span><br><span class="line">            Annotation[] annotations &#x3D; method.getAnnotations();</span><br><span class="line">            for (Annotation annotation : annotations) &#123;</span><br><span class="line">                if (annotation instanceof Description) &#123;</span><br><span class="line">                    Description description &#x3D; (Description) annotation;</span><br><span class="line">                    System.out.println(description.author());</span><br><span class="line">                    System.out.println(description.age());</span><br><span class="line">                    System.out.println(description.desc());</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
</li>
</ul>
<p>参考来源<br><a target="_blank" rel="noopener" href="http://blog.csdn.net/zen99t/article/details/49506919">http://blog.csdn.net/zen99t/article/details/49506919</a><br><a target="_blank" rel="noopener" href="http://blog.csdn.net/zen99t/article/details/49508447">http://blog.csdn.net/zen99t/article/details/49508447</a><br><a target="_blank" rel="noopener" href="http://blog.csdn.net/zen99t/article/details/49512411">http://blog.csdn.net/zen99t/article/details/49512411</a><br><a target="_blank" rel="noopener" href="http://blog.csdn.net/zen99t/article/details/50351575">http://blog.csdn.net/zen99t/article/details/50351575</a><br><a target="_blank" rel="noopener" href="https://www.imooc.com/video/8867">https://www.imooc.com/video/8867</a></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-spring-Transactional"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2018/01/26/spring-Transactional/"
    >一次springboot事务bug的处理</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2018/01/26/spring-Transactional/" class="article-date">
  <time datetime="2018-01-26T03:53:39.000Z" itemprop="datePublished">2018-01-26</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>工作需要将一条数据分别存入es(Elasticsearch)和mysql, 实现方法是: 在 springboot框架里面用@Transactional注解应用的方法保证事务.</p>
<p>抄一条事务的解释:<br><code>事务的作用就是为了保证用户的每一个操作都是可靠的，事务中的每一步操作都必须成功执行，只要有发生异常就回退到事务开始未进行操作的状态。</code></p>
<p>今天发现一条数据存入了mysql, 但是没有存入es, 也就是事务失败了, es出现异常时候没有回退.<br>谷歌等各种搜索都说@Transactional处理事务是可以的.<br>只能尝试和猜测各种写法的问题, 在一次把方法的private改成public后,发现idea没有提示, 难道是因为这个原因? 再次发送数据后,发现事务成功了.</p>
<p>用 <code>public 事务</code> 当关键字在谷歌上一搜发现果然是:<br><code>只有@Transactional 注解应用到public 方法，才能进行事务管理</code></p>
<p>记录一下, 希望以后写事务的时候每次都记住这次大坑.</p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/" rel="tag">java</a></li></ul>

    </footer>
  </div>

    
 
    
</article>

    
    <article
  id="post-mac-java-maven-md"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2017/11/20/mac-java-maven-md/"
    >mac 安装和设置java maven</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2017/11/20/mac-java-maven-md/" class="article-date">
  <time datetime="2017-11-20T10:38:36.000Z" itemprop="datePublished">2017-11-20</time>
</a>    
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <ul>
<li><h3 id="1-安装和设置java"><a href="#1-安装和设置java" class="headerlink" title="1 安装和设置java"></a>1 安装和设置java</h3><ul>
<li><p>1: 搜索官方下载jdk相应版本, 然后双击安装</p>
</li>
<li><p>2: iterm运行</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;usr&#x2F;libexec&#x2F;java_home -V</span><br></pre></td></tr></table></figure>
<p>出现类似</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;Library&#x2F;Java&#x2F;JavaVirtualMachines&#x2F;jdk1.8.0_151.jdk&#x2F;Contents&#x2F;Home</span><br></pre></td></tr></table></figure>
<p>说明安装成功</p>
</li>
<li><p>3: 打开zsh, <code>vim ~/.zshrc</code> 最后面添加</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">export JAVA_HOME&#x3D;$(&#x2F;usr&#x2F;libexec&#x2F;java_home)</span><br></pre></td></tr></table></figure>
<p>保存<br>4: 重新加载zshrc, <code>source ~/.zshrc</code>, 输入<code>echo $JAVA_HOME</code><br>出现</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;Library&#x2F;Java&#x2F;JavaVirtualMachines&#x2F;jdk1.8.0_151.jdk&#x2F;Contents&#x2F;Home</span><br></pre></td></tr></table></figure>
<p>说明安装成功</p>
</li>
</ul>
</li>
<li><h3 id="2-安装和设置maven"><a href="#2-安装和设置maven" class="headerlink" title="2 安装和设置maven"></a>2 安装和设置maven</h3><ul>
<li>用brew安装maven <code>brew install maven</code></li>
<li>item 运行 <code>mvn -v</code><br>出现这样结果说明安装成功<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Maven home: &#x2F;usr&#x2F;local&#x2F;Cellar&#x2F;maven&#x2F;3.5.2&#x2F;libexec</span><br><span class="line">Java version: 1.8.0_151, vendor: Oracle Corporation</span><br><span class="line">Java home: &#x2F;Library&#x2F;Java&#x2F;JavaVirtualMachines&#x2F;jdk1.8.0_151.jdk&#x2F;Contents&#x2F;Home&#x2F;jre</span><br><span class="line">Default locale: zh_CN, platform encoding: UTF-8</span><br><span class="line">OS name: &quot;mac os x&quot;, version: &quot;10.12.6&quot;, arch: &quot;x86_64&quot;, family: &quot;mac&quot;</span><br></pre></td></tr></table></figure></li>
<li>改成阿里源, 参考<a target="_blank" rel="noopener" href="http://blog.csdn.net/liangyihuai/article/details/57406870">来源</a> <code>/usr/local/Cellar/maven/3.5.2/libexec/conf</code> 这个目录下找到setting.xml文件, 打开.<br>在<code>mirrors</code>字段下填入<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;mirror&gt;</span><br><span class="line">        &lt;id&gt;alimaven&lt;&#x2F;id&gt;</span><br><span class="line">        &lt;name&gt;aliyun maven&lt;&#x2F;name&gt;</span><br><span class="line">        &lt;url&gt;http:&#x2F;&#x2F;maven.aliyun.com&#x2F;nexus&#x2F;content&#x2F;groups&#x2F;public&#x2F;&lt;&#x2F;url&gt;</span><br><span class="line">        &lt;mirrorOf&gt;central&lt;&#x2F;mirrorOf&gt;</span><br><span class="line">  &lt;&#x2F;mirror&gt;</span><br></pre></td></tr></table></figure></li>
<li>修改idea的默认maven, 参考<a target="_blank" rel="noopener" href="http://www.jianshu.com/p/43b65774cc15">来源1</a>, <a target="_blank" rel="noopener" href="http://blog.csdn.net/cherrycheng_/article/details/51729272">来源2</a></li>
</ul>
<p>  <img src="https://ww1.sinaimg.cn/large/7293e3b7gy1flopsvyxqoj20s008oq4k.jpg"></p>
<p>  <img src="https://ww1.sinaimg.cn/large/7293e3b7gy1fp8xo07akqj20ri05j3z1.jpg"></p>
</li>
</ul>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
    </footer>
  </div>

    
 
    
</article>

    
  </article>
  

  
  <nav class="page-nav">
    
    <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><span class="space">&hellip;</span><a class="page-number" href="/page/7/">7</a><a class="extend next" rel="next" href="/page/2/">下一页</a>
  </nav>
  
</section>
</div>

      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2015-2022
        <i class="ri-heart-fill heart_icon"></i> 小信
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        Powered by <a href="https://hexo.io" target="_blank">Hexo</a>
        <span class="division">|</span>
        Theme - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>Visitors:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>Views:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="40+岁大龄码农的自我修养"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


    
  </div>
</body>

</html>